/*******************************************************************************
 * Copyright (c) 2007, 2016 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Manumitting Technologies Inc - bug 488721
 ******************************************************************************/

package org.eclipse.ui.internal.quickaccess;

import org.eclipse.jface.resource.DeviceResourceException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ResourceManager;
//import org.eclipse.jface.viewers.StyledCellLabelProvider;
//import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
//import org.eclipse.swt.graphics.TextLayout;
//import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.internal.WorkbenchPlugin;

class QuickAccessEntry {
	boolean firstInCategory;
	boolean lastInCategory;
	QuickAccessElement element;
	QuickAccessProvider provider;
	int[][] elementMatchRegions;
	int[][] providerMatchRegions;

	/**
	 * Provides a rough indicator of how good of a match this entry was to its
	 * filter. Lower values indicate better match quality. A value of 0
	 * indicates the filter string was an exact match to the label or that there
	 * is no filter being applied.
	 */
	private int matchQuality;

	/**
	 * Indicates the filter string was a perfect match to the label or there is
	 * no filter applied
	 *
	 * @see #getMatchQuality()
	 */
	public static final int MATCH_PERFECT = 0;

	/**
	 * Indicates this entry is very relevant for the filter string. Recommended
	 * value for when the filter was found at the start of the element's label
	 * or a complete case sensitive camel case match.
	 *
	 * @see #getMatchQuality()
	 */
	public static final int MATCH_EXCELLENT = 5;

	/**
	 * Indicates this entry is relevant for the filter string. Recommended value
	 * for when the complete filter was found somewhere inside the element's
	 * label or provider.
	 *
	 * @see #getMatchQuality()
	 */
	public static final int MATCH_GOOD = 10;

	/**
	 * Indicates only part of the filter string matches to the element's label.
	 *
	 * @see #getMatchQuality()
	 */
	public static final int MATCH_PARTIAL = 15;

	/**
	 * Creates a new quick access entry from the given element and provider. If
	 * no filter was used to match this entry the element/provider match regions
	 * may be empty and the match quality should be {@link #MATCH_PERFECT}
	 *
	 * @param element
	 *            the element this entry will represent
	 * @param provider
	 *            the provider that owns this entry
	 * @param elementMatchRegions
	 *            list of text regions the filter string matched in the element
	 *            label, possibly empty
	 * @param providerMatchRegions
	 *            list of text regions the filter string matches in the provider
	 *            label, possible empty
	 * @param matchQuality
	 *            a rough indication of how closely the filter matched, lower
	 *            values indicate a better match. It is recommended to use the
	 *            constants available on this class: {@link #MATCH_PERFECT},
	 *            {@link #MATCH_EXCELLENT}, {@link #MATCH_GOOD},
	 *            {@link #MATCH_PARTIAL}
	 */
	QuickAccessEntry(QuickAccessElement element, QuickAccessProvider provider,
			int[][] elementMatchRegions, int[][] providerMatchRegions, int matchQuality) {
		this.element = element;
		this.provider = provider;
		this.elementMatchRegions = elementMatchRegions;
		this.providerMatchRegions = providerMatchRegions;
		this.matchQuality = matchQuality;
	}

	Image getImage(QuickAccessElement element, ResourceManager resourceManager) {
		Image image = findOrCreateImage(element.getImageDescriptor(),
				resourceManager);
		if (image == null) {
			image = WorkbenchImages
					.getImage(IWorkbenchGraphicConstants.IMG_OBJ_ELEMENT);
		}
		return image;
	}

	private Image findOrCreateImage(ImageDescriptor imageDescriptor,
			ResourceManager resourceManager) {
		if (imageDescriptor == null) {
			return null;
		}
		Image image = (Image) resourceManager.find(imageDescriptor);
		if (image == null) {
			try {
				image = resourceManager.createImage(imageDescriptor);
			} catch (DeviceResourceException e) {
				WorkbenchPlugin.log(e);
			}
		}
		return image;
	}

//	public void measure(Event event, TextLayout textLayout,
//			ResourceManager resourceManager, TextStyle boldStyle) {
//		Table table = ((TableItem) event.item).getParent();
//		textLayout.setFont(table.getFont());
//		event.width = 0;
//		switch (event.index) {
//		case 0:
//			if (firstInCategory || providerMatchRegions.length > 0) {
//				textLayout.setText(provider.getName());
//				if (boldStyle != null) {
//					for (int[] matchRegion : providerMatchRegions) {
//						textLayout.setStyle(boldStyle, matchRegion[0], matchRegion[1]);
//					}
//				}
//			} else {
//				textLayout.setText(""); //$NON-NLS-1$
//			}
//			break;
//		case 1:
//			textLayout.setText(element.getLabel());
//			// Two situations for measuring icons:
//			// - command with very large icon image (500x500) [scale down]
//			// - command with normal image (16x16) but small text-height (8pt)
//			Image image = getImage(element, resourceManager);
//			Rectangle imageRect = image.getBounds();
//			Rectangle textBounds = textLayout.getBounds();
//			int iconSize = imageRect.height;
//			// Heuristic: only scale image if has double the pixels
//			if (iconSize > 16 && iconSize >= 2 * textBounds.height) {
//				// image will be scaled down to fit
//				iconSize = textBounds.height;
//			}
//			// include additional line 1 for category separator
//			event.height = Math.max(event.height, iconSize + 3);
//			event.width += iconSize + 4;
//			if (boldStyle != null) {
//				for (int[] matchRegion : elementMatchRegions) {
//					textLayout.setStyle(boldStyle, matchRegion[0], matchRegion[1]);
//				}
//			}
//			break;
//		}
//		Rectangle rect = textLayout.getBounds();
//		event.width += rect.width + 4;
//		event.height = Math.max(event.height, rect.height + 2);
//	}
//
//	public void paint(Event event, TextLayout textLayout,
//			ResourceManager resourceManager, TextStyle boldStyle, Color grayColor) {
//		final Table table = ((TableItem) event.item).getParent();
//		textLayout.setFont(table.getFont());
//		switch (event.index) {
//		case 0:
//			if (firstInCategory || providerMatchRegions.length > 0) {
//				textLayout.setText(provider.getName());
//				if (boldStyle != null) {
//					for (int[] matchRegion : providerMatchRegions) {
//						textLayout.setStyle(boldStyle, matchRegion[0],
//								matchRegion[1]);
//					}
//				}
//				if (grayColor != null && providerMatchRegions.length > 0 && !firstInCategory) {
//					event.gc.setForeground(grayColor);
//				}
//				Rectangle availableBounds = ((TableItem) event.item).getTextBounds(event.index);
//				Rectangle requiredBounds = textLayout.getBounds();
//				textLayout.draw(event.gc, availableBounds.x + 1, availableBounds.y
//						+ (availableBounds.height - requiredBounds.height) / 2);
//			}
//			break;
//		case 1:
//			String label = element.getLabel();
//			if (element instanceof CommandElement) {
//				CommandElement commandElement = (CommandElement) element;
//				String binding = commandElement.getBinding();
//				if (binding != null) {
//					StyledString styledString = StyledCellLabelProvider.styleDecoratedString(label,
//							StyledString.QUALIFIER_STYLER, new StyledString(commandElement
//									.getCommand()));
//					StyleRange[] styleRanges = styledString.getStyleRanges();
//					for (StyleRange styleRange : styleRanges) {
//						textLayout.setStyle(styleRange, styleRange.start,
//								styleRange.start + styleRange.length);
//					}
//				}
//			}
//			// draw images to fit square area sized by the text area
//			Image image = getImage(element, resourceManager);
//			Rectangle availableBounds = ((TableItem) event.item).getTextBounds(event.index);
//			Rectangle requiredBounds = textLayout.getBounds();
//			Rectangle imageBounds = image.getBounds();
//			// 3 = top + bottom + category lines
//			int maxImageSize = availableBounds.height - 3;
//			// preserve aspect ratio
//			int destHeight = Math.min(imageBounds.height, maxImageSize);
//			int destWidth = destHeight * imageBounds.width / imageBounds.height;
//			// and centre within available space; remove 1 from height for
//			// category separator
//			int startX = (maxImageSize - destWidth) / 2;
//			int startY = (availableBounds.height - 1 - destHeight) / 2;
//			event.gc.drawImage(image, 0, 0, imageBounds.width, imageBounds.height,
//					availableBounds.x + startX, availableBounds.y + startY,
//					destWidth, destHeight);
//			textLayout.setText(label);
//			if (boldStyle != null) {
//				for (int[] matchRegion : elementMatchRegions) {
//					textLayout.setStyle(boldStyle, matchRegion[0], matchRegion[1]);
//				}
//			}
//			textLayout.draw(event.gc, availableBounds.x + maxImageSize + 4,
//					availableBounds.y + (availableBounds.height - requiredBounds.height) / 2);
//			break;
//		}
//		if (lastInCategory) {
//			if (grayColor != null)
//				event.gc.setForeground(grayColor);
//			Rectangle bounds = ((TableItem)event.item).getBounds(event.index);
//			event.gc.drawLine(Math.max(0, bounds.x - 1), bounds.y + bounds.height - 1, bounds.x + bounds.width, bounds.y
//					+ bounds.height - 1);
//		}
//	}

	/**
	 * @param event
	 */
	public void erase(Event event) {
		// We are only custom drawing the foreground.
		event.detail &= ~SWT.FOREGROUND;
	}

	/**
	 * Provides a rough indicator of how good of a match this entry was to its
	 * filter. Lower values indicate better match quality. A value of
	 * {@link #MATCH_PERFECT} indicates the filter string was an exact match to
	 * the label or that there is no filter being applied.
	 *
	 * @return Returns the match quality
	 */
	public int getMatchQuality() {
		return matchQuality;
	}

}